import { IStack, IObjStack } from "./base";

export namespace NumNet {
  /** 模仿C#栈；OK
   * 先进后出。
   */
  export class Stack<T> {
    private stack: Array<T>;
    constructor(data?: T[]) {
      this.stack = data || [];
    }
    /** 栈中元素个数 */
    get length() {
      return this.stack.length;
    }

    /** 是否为空栈 */
    get isEmpty() {
      return this.length === 0;
    }

    /** 压栈；
     * 将元素存入栈顶。
     * @param item 元素
     * @returns 返回栈长度
     */
    push(item: T) {
      return this.stack.push(item);
    }

    /** 出栈
     *
     * @returns 出栈的元素
     */
    pop() {
      return this.stack.pop();
    }

    /** 显示栈顶元素;
     * 不影响栈的长度;
     * 计算属性；
     * @returns 显示栈顶元素
     */
    get peek() {
      return this.stack.at(-1);
    }

    /** 是否包含某个元素
     *
     * @param item 某个元素
     * @returns boolean
     */
    contains(item: T) {
      return this.stack.includes(item);
    }

    /** 复制栈到一个新的数组中
     *
     * @returns 返回该数组
     */
    toArray() {
      const resArr = [...this.stack];
      return resArr.reverse();
    }

    toSting(): string {
      return this.peek + " <...> ";
    }
  }

  /** 栈类 */
  export class ArrayStack<T> implements IStack<T> {
    private itemStack: T[];
    /** 栈的构造函数；
     * 初始化栈，以数组为基础。
     */
    constructor() {
      this.itemStack = [];
    }
    pop(): T | undefined {
      return this.itemStack.pop();
    }
    push(item: T): number {
      return this.itemStack.push(item);
    }
    peek(): T | undefined {
      return this.itemStack.at(-1);
    }
    toStr(): string {
      if (this.size == 0) {
        return `null`;
      } else if (this.size === 1) {
        return `${this.peek()}`;
      } else {
        return `${this.peek()}<=[...]`;
      }
    }
    clear(): void {
      this.itemStack = [];
    }
    get size(): number {
      return this.itemStack.length;
    }
    get isEmpty(): boolean {
      return this.itemStack.length === 0;
    }
  }

  /** 实现数据结构栈;
   * O(1)
   */
  export class ObjStack<T> {
    private items: IObjStack<T>;
    private count: number;
    constructor() {
      this.count = 0;
      this.items = {};
    }

    /** 判断栈是否为空 */
    get isEmpty() {
      return this.count === 0;
    }

    /** 获取栈内元素数量 */
    get size() {
      return this.count;
    }

    /**入栈
     *
     * @param item
     */
    push(item: T) {
      this.items[this.count] = item;
      this.count++;
    }

    /** 出栈
     *
     * @returns
     */
    pop() {
      if (this.isEmpty) {
        return undefined;
      }
      this.count--;
      const result = this.items[this.count];
      delete this.items[this.count];
      return result;
    }

    /** 返回栈顶元素
     *
     * @returns
     */
    peek() {
      if (this.isEmpty) {
        return undefined;
      }
      return this.items[this.count - 1];
    }

    /** 清空栈内元素
     *
     */
    clear() {
      this.items = {};
      this.count = 0;
    }

    /** 将栈内元素转为字符串
     *
     * @returns
     */
    toString() {
      if (this.isEmpty) {
        return "";
      }
      let objString = `${this.items[0]}`;
      for (let i = 0; i < this.count; i++) {
        objString = `${objString},${this.items[i]}`;
      }
      return objString;
    }
  }

  /** 模仿C#队列；OK
   * 先进先出。
   */
  export class Queue<T> {
    private queue: Array<T> = [];

    /** 获取队列中包含的元素个数 */
    get count() {
      return this.queue.length;
    }

    /** 是否为空队列 */
    get isEmpty() {
      return this.count === 0;
    }

    /** 入队；
     * 向队列的末尾处添加一个对象。
     * @param item 元素
     * @returns 返回队列长度
     */
    enqueue(item: T) {
      return this.queue.push(item);
    }

    /** 出队列
     * 移除并返回在队列开头的对象
     * @returns 出栈的元素
     */
    dequeue() {
      return this.queue.shift();
    }

    /** 查看队首元素
     *
     * @returns
     */
    peek() {
      return this.queue[0];
    }

    /** 判断某个元素是否在队列中
     *
     * @param item 某个元素
     * @returns boolean
     */
    // contains(item: T) {
    //   return this.queue.includes(item);
    // }

    /** 复制队列到一个新的数组中
     *
     * @returns 数组
     */
    toArray() {
      return [...this.queue];
    }
  }

  // 声明队列内部对象类型
  interface IQueueObj {
    [propName: number]: any;
  }

  /**
   * 实现队列
   *    队列的基础方法: 入队、出队、返回队首元素、获取队列大小、判断队列是否为空、清空队列、获取队列内所有数据
   */
  export class ObjQueue {
    private count: number;
    private lowestCount: number;
    private items: IQueueObj;

    // 构造器
    constructor() {
      // 队列中的三个必要变量: 队列大小、队首元素、队列对象
      this.count = 0;
      this.lowestCount = 0;
      this.items = {};
    }

    // 入队
    enqueue(item: any) {
      // 队列的末尾添加元素: 将队列的大小作为key
      this.items[this.count] = item;
      this.count++;
    }

    // 出队
    dequeue() {
      if (this.isEmpty()) {
        return undefined;
      }
      const result = this.items[this.lowestCount];
      // 删除队首元素
      delete this.items[this.lowestCount];
      // 队首元素自增
      this.lowestCount++;
      return result;
    }

    // 返回队首元素
    peek() {
      if (this.isEmpty()) {
        return undefined;
      }
      return this.items[this.lowestCount];
    }

    // 队列大小: 队列的大小 - 队首元素
    size() {
      return this.count - this.lowestCount;
    }

    // 判断队列是否为空
    isEmpty() {
      return this.count - this.lowestCount === 0;
    }

    // 清空队列
    clear() {
      this.count = 0;
      this.lowestCount = 0;
      this.items = {};
    }

    // 获取队列内所有数据
    toString() {
      if (this.isEmpty()) {
        return "";
      }
      let objString = `${this.items[this.lowestCount]}`;
      for (let i = this.lowestCount + 1; i < this.count; i++) {
        objString = `${objString},${this.items[i]}`;
      }
      return objString;
    }
  }
}

class Stack<T> {
  private stk: T[];

  constructor() {
    this.stk = [];
  }

  // 向栈中添加一个元素
  push(x: T): void {
    this.stk.push(x);
  }

  // 从栈中弹出一个元素
  pop(): T | undefined {
    return this.stk.pop();
  }

  // 交换栈顶的两个元素
  swap(): void {
    if (this.stk.length < 2) return;
    // 交换栈顶的两个元素
    [this.stk[this.stk.length - 1], this.stk[this.stk.length - 2]] = [
      this.stk[this.stk.length - 2],
      this.stk[this.stk.length - 1],
    ];
  }

  // 在栈顶添加一个与栈顶元素相同的元素
  dup(): void {
    this.stk.push(this.stk.at(-1)!);
  }

  // 将栈中的元素反转
  reverse(): void {
    this.stk.reverse();
  }

  // 返回栈中元素的数量
  get size(): number {
    return this.stk.length;
  }

  // 判断栈是否为空
  isEmpty(): boolean {
    return this.stk.length === 0;
  }
}
